home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $Source: dh1:network/parnet/Sana2/Sources/sana2_funcs.c,v $
- ** $State: Exp $
- ** $Revision: 37.2 $
- ** $Date: 93/12/17 22:07:45 $
- ** $Author: S.A.Pechler $
- **
- ** Amiga SANA-II Example PARnet device driver.
- **
- ** SPAR Sana-II functions.
- **
- ** Based on the Amiga SANA-II Example SLIP device driver code by bj,
- ** which is (C) Copyright 1992 Commodore-Amiga, Inc.
- ** the rhslip.device by Olaf Seibert <rhialto@mbfys.kun.nl>, and on
- ** the agnet.device code by ppessi <Pekka.Pessi@hut.fi>, which is
- ** Copyright (c) 1993 AmiTCP/IP Group,
- ** Helsinki University of Technology, Finland.
- ** All rights reserved.
- **
- */
-
- #include "device_protos.h"
-
- /*
- **
- ** PerformIO
- **
- ** PerformIO actually dispatches an io request. It might be called from
- ** the Unit process, or directly from BeginIO (thus on the caller's schedule)
- */
- VOID PerformIO(struct IOSana2Req *ios2)
- {
- struct SPARDevUnit *sdu;
-
- sdu = (struct SPARDevUnit *)ios2->ios2_Req.io_Unit; /* get the Unit pointer */
-
- ios2->ios2_Req.io_Error = NULL; /* no error so far */
-
- switch(ios2->ios2_Req.io_Command)
- {
- case CMD_READ: ReadPacket(sdu,ios2);
- break;
-
- case CMD_WRITE: debug(("PerformIO: call to CMD_WRITE\n"))
- WritePacket(sdu,ios2);
- break;
-
- case S2_DEVICEQUERY: debug(("PerformIO: call to S2_DEVICEQUERY\n"))
- DeviceQuery(sdu,ios2);
- break;
-
- case S2_GETSTATIONADDRESS: debug(("PerformIO: call to S2_GETSTATIONADDRESS\n"))
- GetStationAddress(sdu,ios2);
- break;
-
- case S2_CONFIGINTERFACE: debug(("PerformIO: call to S2_CONFIGINTERFACE\n"))
- ConfigInterface(sdu,ios2);
- break;
-
- case S2_BROADCAST: debug(("PerformIO: call to S2_BROADCAST\n"))
- BroadcastPacket(sdu,ios2);
- break;
- case S2_ADDMULTICASTADDRESS:
- case S2_DELMULTICASTADDRESS:
- case S2_MULTICAST: ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- debug(("PerformIO: call to not supported function\n"))
-
- TermIO(ios2);
- break;
-
- case S2_TRACKTYPE: debug(("PerformIO: call to S2_TRACKTYPE\n"))
- TrackType(sdu,ios2);
- break;
-
- case S2_UNTRACKTYPE: debug(("PerformIO: call to S2_UNTRACKTYPE\n"))
- UnTrackType(sdu,ios2);
- break;
-
- case S2_GETTYPESTATS: debug(("PerformIO: call to S2_GETTYPESTATS\n"))
- GetTypeStats(sdu,ios2);
- break;
-
- case S2_GETSPECIALSTATS: debug(("PerformIO: call to S2_GETSPECIALSTATS\n"))
- GetSpecialStats(sdu,ios2);
- break;
-
- case S2_GETGLOBALSTATS: debug(("PerformIO: call to S2_GETGLOBALSTATS\n"))
- GetGlobalStats(sdu,ios2);
- break;
-
- case S2_ONEVENT: debug(("PerformIO: call to S2_ONEVENT\n"))
- OnEvent(sdu,ios2);
- break;
-
- case S2_READORPHAN: debug(("PerformIO: call to S2_READORPHAN\n"))
- ReadOrphan(sdu,ios2);
- break;
-
- case S2_ONLINE: debug(("PerformIO: call to S2_ONLINE\n"))
- Online(sdu,ios2);
- break;
-
- case S2_OFFLINE: debug(("PerformIO: call to S2_OFFLINE\n"))
- Offline(sdu,ios2);
- break;
-
- default: debug(("PerformIO: call to unknown function\n"))
- ios2->ios2_Req.io_Error = IOERR_NOCMD;
- TermIO(ios2);
- break;
- }
- }
-
- /*
- ** This function returns any device specific statistics that
- ** we may have. Unfortunately, we don't have any SPAR specific
- ** statistics.
- */
- VOID GetSpecialStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct Sana2SpecialStatHeader *stats;
-
- stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
-
- stats->RecordCountSupplied = 0;
- TermIO(ios2);
- }
-
- /*
- ** This function returns the global statistics for the
- ** spar device.
- */
- VOID GetGlobalStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct Sana2DeviceStats *stats;
-
- if (stats = (struct Sana2DeviceStats *)ios2->ios2_StatData)
- {
- stats->PacketsReceived = sdu->sdu_Stats.PacketsReceived;
- stats->PacketsSent = sdu->sdu_Stats.PacketsSent;
- stats->BadData = sdu->sdu_Stats.BadData;
- stats->Overruns = sdu->sdu_Stats.Overruns;
- stats->UnknownTypesReceived = sdu->sdu_Stats.UnknownTypesReceived;
- stats->Reconfigurations = sdu->sdu_Stats.Reconfigurations;
- stats->LastStart.tv_secs = sdu->sdu_Stats.LastStart.tv_secs;
- stats->LastStart.tv_micro = sdu->sdu_Stats.LastStart.tv_micro; /* Rhialto */
-
- ios2->ios2_Req.io_Error = 0;
- ios2->ios2_WireError = 0;
- }
- else
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
- ios2->ios2_WireError = S2WERR_NULL_POINTER;
- }
- TermIO(ios2);
- }
-
- /*
- ** This function returns statistics for a specific
- ** type of packet that is being tracked.
- **
- */
- VOID GetTypeStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct Sana2PacketTypeStats *stats;
- struct SuperS2PTStats *sstats;
-
- if (stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData)
- {
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- sstats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- while(sstats->ss_Node.mln_Succ)
- {
- /* Is this the desired packet type? */
- if(ios2->ios2_PacketType == sstats->ss_PType)
- {
- stats->PacketsSent = sstats->ss_Stats.PacketsSent;
- stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
- stats->BytesSent = sstats->ss_Stats.BytesSent;
- stats->BytesReceived = sstats->ss_Stats.BytesReceived;
- stats->PacketsDropped = sstats->ss_Stats.PacketsDropped;
- break;
- }
- sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
- }
- ReleaseSemaphore(&sdu->sdu_ListLock);
- if(!sstats->ss_Node.mln_Succ)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- }
- else
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
- ios2->ios2_WireError = S2WERR_NULL_POINTER;
- }
- TermIO(ios2);
- }
-
- /*
- ** This function adds a packet type to the list
- ** of those that are being tracked.
- */
- VOID TrackType(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- BOOL TypeFound=FALSE;
- struct SuperS2PTStats *stats;
-
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- /* Check in the list is this packet is already been tracked */
- while(stats->ss_Node.mln_Succ)
- {
- if(ios2->ios2_PacketType == stats->ss_PType)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
- TypeFound=TRUE;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
-
-
- if(!TypeFound) /* Type not in list? */
- if(stats = AllocMem(sizeof(struct SuperS2PTStats),MEMF_CLEAR|MEMF_PUBLIC))
- { /* Add packet type to the list */
- sdu->sdu_TrackP = TRUE;
- stats->ss_PType = ios2->ios2_PacketType;
-
- debug(("TrackType: Added Type: %04lx.\n",ios2->ios2_PacketType))
-
- AddTail((struct List *)&sdu->sdu_Track,(struct Node *)stats);
- }
- ReleaseSemaphore(&sdu->sdu_ListLock);
-
- TermIO(ios2);
- }
-
- /*
- ** This function removes a packet type from the
- ** list of those that are being tracked.
- */
- VOID UnTrackType(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct SuperS2PTStats *stats;
- struct SuperS2PTStats *stats_next;
- BOOL TypeFound = FALSE;
-
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- while(stats->ss_Node.mln_Succ)
- {
- stats_next = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- if(ios2->ios2_PacketType == stats->ss_PType)
- {
- Remove((struct Node *)stats);
- FreeMem(stats,sizeof(struct SuperS2PTStats));
- TypeFound = TRUE;
- break;
- }
- stats = stats_next;
- }
- if(!TypeFound) /* Type not found in list */
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- if(!stats->ss_Node.mln_Succ) /* list is empty */
- sdu->sdu_TrackP=FALSE; /* reset track flag */
- ReleaseSemaphore(&sdu->sdu_ListLock);
-
- TermIO(ios2);
- }
-
- /*
- ** This function is called whenever we receive a packet
- ** from the PARnet device driver.
- **
- */
- VOID PacketReceived(struct SPARDevUnit *sdu, ULONG length)
- {
- struct SuperS2PTStats *stats;
-
- sdu->sdu_Stats.PacketsReceived++;
-
- /* Packet tracking enabled ? */
- if(sdu->sdu_TrackP)
- {
- stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- /* Check if this packet type is on the tracking list */
- while(stats->ss_Node.mln_Succ)
- {
- if( *(UWORD *)(sdu->sdu_RxBuff+SADDR_LEN*2) == stats->ss_PType)
- {
- /* Found entry for this packet type, updating stats */
- stats->ss_Stats.PacketsReceived++;
- stats->ss_Stats.BytesReceived+=length;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- }
- }
-
- /*
- ** This function is called whenever a packet is
- ** sent to the PARnet device driver.
- */
- VOID PacketSent(struct SPARDevUnit *sdu, ULONG length)
- {
- struct SuperS2PTStats *stats;
-
- sdu->sdu_Stats.PacketsSent++;
-
- /* Packet tracking enabled ? */
- if(sdu->sdu_TrackP)
- {
- stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- /* Check if this packet type is on the tracking list */
- while(stats->ss_Node.mln_Succ)
- {
-
- if( *(UWORD *)(sdu->sdu_TxBuff+SADDR_LEN*2) == (UWORD)stats->ss_PType)
- {
- /* Found entry for this packet type, updating stats */
-
- debug(("PacketSent: Tracked packet type: %04lx.\n",stats->ss_PType))
-
- stats->ss_Stats.PacketsSent++;
- stats->ss_Stats.BytesSent+=length;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- }
- }
-
- /*
- ** This function is called whenever a packet that
- ** is too large is received.
- */
- VOID PacketOverrun(struct SPARDevUnit *sdu)
- {
- sdu->sdu_Stats.Overruns++;
- DoEvent(sdu, S2EVENT_RX);
- }
-
- /*
- ** This function is called whenever a packet with
- ** garbage data is encountered.
- */
- VOID ReceivedGarbage(struct SPARDevUnit *sdu)
- {
- sdu->sdu_Stats.BadData++;
- DoEvent(sdu, S2EVENT_RX);
- }
-
- /*
- ** This function is called whenever a packet
- ** is dropped by the SPAR driver.
- */
- VOID PacketDropped(struct SPARDevUnit *sdu)
- {
- struct SuperS2PTStats *stats;
-
- /* Packet tracking enabled ? */
- if(sdu->sdu_TrackP)
- {
- stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
-
- /* Check if this packet type is on the tracking list */
- while(stats->ss_Node.mln_Succ)
- {
-
- if( *(UWORD *)(sdu->sdu_TxBuff+SADDR_LEN*2) == (UWORD)stats->ss_PType)
- {
- /* Found entry for this packet type, updating stats */
- stats->ss_Stats.PacketsDropped++;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- }
- }
-
- /*
- ** This function is called whenever an orphan packet
- ** is received (Routine from the agnet device).
- */
- VOID
- ReceivedOrphan(struct SPARDevUnit *sdu)
- {
- sdu->sdu_Stats.UnknownTypesReceived++;
- }
-
- /*
- ** This function is used to locate an IO request in a linked
- ** list and abort it if found.
- */
- LONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
- {
- struct Node *node, *next;
- LONG result=IOERR_NOCMD;
-
- node = (struct Node *)minlist->mlh_Head;
-
- while(node->ln_Succ)
- {
- next = node->ln_Succ;
-
- if(node == (struct Node *)ios2)
- {
- Remove((struct Node *)ios2);
- ios2->ios2_Req.io_Error = IOERR_ABORTED;
- TermIO(ios2);
- result = 0;
- }
- node = next;
- }
- return(result);
- }
-
- /*
- ** This function handles S2_CONFIGINTERFACE commands.
- */
- VOID ConfigInterface(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- UBYTE tempaddr; /* unvalidated hardware address */
-
- /* Note: we may only be configured once. */
- if(!(sdu->sdu_State & SPARUF_CONFIG))
- {
- /* A PARnet network can only handle addresses of 1 octet, so
- * only the last octet of the given ethernet address is used (an
- * ethernetaddress occupies the first 6 bytes in ios2_SrcAddr) */
- tempaddr = ios2->ios2_SrcAddr[0];
-
- debug(("ConfigInterface: Hw.addr. set to :%d (%08lx%04x).\n",(LONG)tempaddr,*(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4)))
-
- /* check the address before using, take over when it's ok. */
- if ((tempaddr!=0) && (tempaddr!=255))
- sdu->sdu_StAddr = tempaddr;
-
- sdu->sdu_State |= SPARUF_CONFIG;
-
- if(!(OpenPARnet(sdu)))
- { /* failed to open */
- sdu->sdu_State &= ~SPARUF_CONFIG;
- ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- }
- else
- {
- /* Sorry, we're already configured. */
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
- }
- TermIO(ios2);
- }
-
-
- /*
- ** This function handles S2_BROADCAST commands.
- ** It is very limited, because PARnet does not support packet broadcast.
- ** Only ARP broadcasts will be accepted and processed internally.
- **
- */
- VOID BroadcastPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct BufferManagement *bm;
- struct ARPframePacket *ARPreqPacket;
- /* ARP response packet */
- struct ARPframePacket ARPrespPacket = {0,0,ETHERTYPE_ARP,ARPHRD_ETHER,ETHERTYPE_IP,6,4,ARPOP_REPLY,0,0,0,0};
-
- if (sdu->sdu_DestAddr)
- {
- memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES); /* Clear dest.addr. */
- ios2->ios2_DstAddr[0]=sdu->sdu_DestAddr; /* fill in destination address */
- WritePacket(sdu,ios2); /* Just write it to the other end */
- }
- else
- {
- bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
-
- /* Copy the data out of the packet into our temporary buffer. */
- if((*bm->bm_CopyFromBuffer)(sdu->sdu_RxBuff+SHDR_LEN,ios2->ios2_Data,ios2->ios2_DataLength))
- {
- ARPreqPacket=(struct ARPframePacket *)sdu->sdu_RxBuff; /* Pointer to ARP frame */
-
- if ((UWORD)ios2->ios2_PacketType == ETHERTYPE_ARP) /* ARP broadcast? */
- {
- debug(("ARP Req (%ld): %08lx%08lx%08lx%08lx%08lx%08lx",ios2->ios2_DataLength,*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12),*(LONG *)(sdu->sdu_RxBuff+16),*(LONG *)(sdu->sdu_RxBuff+20)))
-
- ARPrespPacket.ar_dstaddr=sdu->sdu_StAddr; /* frame target h/w address (myself) */
- /* frame type already filled in
- * with ETHERTYPE_ARP as default */
-
- /* copy sender's addresses to target address fields */
- ARPrespPacket.ar_tpa=ARPreqPacket->ar_spa;
- memcpy(&ARPrespPacket.ar_tha,ARPreqPacket->ar_sha,EADDR_LEN);
-
- /* copy target IP address to sender's IP address field */
-
- ARPrespPacket.ar_spa=ARPreqPacket->ar_tpa;
-
- /* calculate the target hardware address from the last octet of the
- * target IP address */
-
- ARPrespPacket.ar_sha[0]=
-
- /* Fill in also hardware source address */
- ARPrespPacket.ar_srcaddr= (UBYTE)ARPrespPacket.ar_spa;
-
- /* copy packet to receiver buffer */
- memcpy(sdu->sdu_RxBuff,&ARPrespPacket,sizeof(ARPrespPacket));
-
- debug(("Tx ARP resp (%ld): %08lx%08lx%08lx%08lx%08lx%08lx",sizeof(ARPrespPacket),*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12),*(LONG *)(sdu->sdu_RxBuff+16),*(LONG *)(sdu->sdu_RxBuff+20)))
-
- GotPacket(sdu,sizeof(ARPrespPacket));
- }
- else /* non-ARP broadcast packet */
- {
- debug(("Unsupported broadcast packet type\n"))
- PacketDropped(sdu); /* Can't handle address 255 */
- }
- }
- else
- {
- /* Something went wrong...*/
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(sdu,S2EVENT_BUFF);
- }
- TermIO(ios2);
- }
- }
-
- /*
- ** This function handles S2_GETSTATIONADDRESS commands.
- **
- ** PARnet uses only 1 octet, so only the 1th byte in ios2_SrcAddr will be
- ** filled.
- **
- ** Rhialto: What we want is the config file address as hardware
- ** address, and the S2_CONFIGINTERFACE address as current address.
- **
- */
-
- VOID GetStationAddress(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- /* Clear address space */
- memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES);
- memset(ios2->ios2_SrcAddr, 0, SANA2_MAX_ADDR_BYTES);
-
- /* Place our current address in first position of Src_Addr.
- * And our hardware address (given in spar#.config) in Dst_Addr.
- */
- ios2->ios2_SrcAddr[0]=sdu->sdu_StAddr;
- ios2->ios2_DstAddr[0]=sdu->sdu_HwAddr;
-
- debug(("GetStationAddr: %08lx%04lx.\n",*(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4)))
-
- TermIO(ios2);
- }
-
- /*
- ** This function handles S2_DEVICEQUERY comands.
- */
- VOID DeviceQuery(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- struct Sana2DeviceQuery *sdq;
-
- sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
-
- sdq->AddrFieldSize = 48; /* six bytes (48 bits) hardware address */
- /* this is for Ethernet compatibility, */
- /* Spar uses 1 byte h/w addresses. */
- sdq->MTU = SPAR_MTU; /* max. trans. unit */
- sdq->BPS = SPAR_SPEED; /* PARnet has fixed speed */
- sdq->HardwareType = S2WireType_Ethernet; /* fake! */
-
- sdq->DevQueryFormat = NULL;
- sdq->DeviceLevel = NULL;
- sdq->SizeSupplied = sizeof(struct Sana2DeviceQuery);
- TermIO(ios2);
- }
-
- /*
- ** This function is used for handling CMD_WRITE
- ** commands.
- */
- VOID WritePacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
-
- /* Make sure that we are online. */
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- /* Make sure it's a legal length. */
- if(ios2->ios2_DataLength <= SPAR_MTU)
- {
- /* See if our PARnet CMD_WRITE command is busy. If it's not, send
- * the IO request to SendPacket. */
- if(CheckIO((struct IORequest *)sdu->sdu_ParTx))
- {
- WaitIO((struct IORequest *)sdu->sdu_ParTx);
- SendPacket(sdu, ios2);
- }
- else
- {
- /* We'll have to queue the packet for later...*/
- ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_Tx,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
- }
- else
- {
- /* Sorry, the packet is too long! */
- ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2);
- DoEvent(sdu,S2EVENT_TX);
- }
- }
- else
- {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
- }
-
- /*
- ** This routine handles CMD_READ commands. We
- ** always queue these unless we're offline.
- */
- VOID ReadPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
-
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- /* Queue it... */
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_Rx,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
- else
- {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
- }
-
- /*
- ** This routine handles CMD_READORPHAN commands. We
- ** always queue these unless we're offline.
- **
- */
- VOID ReadOrphan(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
-
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- /* Queue it...*/
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_RxOrph,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
- else
- {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
- }
-
- /*
- ** This routine handles S2_ONEVENT commands.
- */
- VOID OnEvent(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
-
- switch(ios2->ios2_WireError)
- {
- /* Special case. We may already be online, in which
- * case the IO request should return immediately. Otherwise
- * we queue it for later. */
-
- case S2EVENT_ONLINE:
- if(sdu->sdu_State & SPARUF_ONLINE)
- TermIO(ios2);
- else
- {
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
- break;
-
- /* Same as with S2EVENT_ONLINE, but the opposite
- * happens. */
- case S2EVENT_OFFLINE:
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
- else
- TermIO(ios2);
- break;
-
- /* Just queue everything else. */
- default:
- ObtainSemaphore(&sdu->sdu_ListLock);
- AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
- ReleaseSemaphore(&sdu->sdu_ListLock);
- break;
- }
- }
-
- /*
- ** This routine gets the current system time and stores
- ** it in our global statistics structure.
- */
-
- VOID MarkTimeOnline(struct SPARDevUnit *sdu)
- {
- register struct Library *TimerBase;
- struct timerequest *treq;
-
- if(treq = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
- {
- if(!OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)treq,NULL))
- {
- TimerBase = (struct Library *)treq->tr_node.io_Device;
- GetSysTime(&sdu->sdu_Stats.LastStart);
- CloseDevice((struct IORequest *)treq);
- }
- FreeMem(treq,sizeof(struct timerequest));
- }
- }
-
- /*
- ** This routine handles CMD_ONLINE commands.
- */
- VOID Online(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
-
- if(!(sdu->sdu_State & SPARUF_ONLINE))
- {
- /* We're offline. Try to go online. */
- if(OpenPARnet(sdu))
- {
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- /* In case someone wants to know...*/
- DoEvent(sdu, S2EVENT_ONLINE);
- }
- else
- {
- /* Sorry, the attempt to go online failed. */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- }
- }
- else
- {
- /* A general problem occured. */
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- }
- TermIO(ios2);
- }
-
- /*
- ** This routine handles CMD_OFFLINE commands.
- */
- VOID Offline(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
- {
- TermIO(ios2);
-
- if(sdu->sdu_State & SPARUF_ONLINE)
- {
- /* We're online, so shut everything down. */
- ClosePARnet(sdu);
- DoOffline(sdu);
- DoEvent(sdu,S2EVENT_OFFLINE);
- }
- }
-
- /*
- ** This routine is called whenever an "important"
- ** SANA-II event occurs.
- */
- VOID DoEvent(struct SPARDevUnit *sdu, ULONG event)
- {
- struct IOSana2Req *ios2;
- struct IOSana2Req *ios2_next;
-
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- ios2 = (struct IOSana2Req *)sdu->sdu_Events.mlh_Head;
-
- while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
- {
- ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
-
- /* Is this the event they are looking for? */
- if(ios2->ios2_WireError == event)
- {
- Remove((struct Node *)ios2);
- TermIO(ios2);
- }
- ios2 = ios2_next;
- }
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
-
- /*
- ** This routine is called whenever the device needs to
- ** be taken offline. We return any pending CMD_READ's
- ** or CMD_WRITE's to their senders.
- */
- VOID DoOffline(struct SPARDevUnit *sdu)
- {
- struct IOSana2Req *ios2;
-
- ObtainSemaphore(&sdu->sdu_ListLock);
-
- while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
-
- while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2);
- }
- ReleaseSemaphore(&sdu->sdu_ListLock);
- }
-